package org.yu.team2023.flashdays;

import com.mojang.logging.LogUtils;

import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityAttributeModificationEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraftforge.event.entity.living.LivingHealEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.registries.RegistryObject;
import org.slf4j.Logger;

@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class ModAttributes {
    private static final Logger LOGGER= LogUtils.getLogger();
    public static final RegistryObject<Attribute> DAMAGE_RESISTANCE = attribute("damage_resistance", "伤害抗性", 0, Integer.MIN_VALUE, 100, false);
    public static final RegistryObject<Attribute> WEAKNESS_SPECIAL_ATTACK = attribute("weakness_special_attack", "弱点特攻", 0, 0, Integer.MAX_VALUE, false);
    public static final RegistryObject<Attribute> RANGED_DAMAGE = attribute("ranged_damage", "远程伤害", 0, 0,Integer.MAX_VALUE, false);
    public static final RegistryObject<Attribute> REFLEXIVE_INJURY = attribute("reflexive_injury", "反弹伤害", 0, 0, 100, false);
    public static final RegistryObject<Attribute> DODGE = attribute("dodge", "闪避", 0.01, 0, 99.99, false);
    public static final RegistryObject<Attribute> ADDITION_ATTACK = attribute("addition_attack", "追加攻击", 0, 0, Integer.MAX_VALUE, false);
      public static final RegistryObject<Attribute> COOLING_REDUCTION =attribute("cd_reduction", "冷却缩减", 0, 0, 99, true);
    public static final RegistryObject<Attribute> USE_SPEED_UP = attribute("use_speed_up", "快速使用", 0, 0, 99, false);

    public static final RegistryObject<Attribute> CRIT = attribute("crit", "暴击率", 5, 0, Integer.MAX_VALUE,false);
    public static final RegistryObject<Attribute> CRIT_EFFECT =attribute("crit_effect", "暴击效果", 50, 0, Integer.MAX_VALUE,false);
    public static final RegistryObject<Attribute> HEALTH_STEAL = attribute("health_steal", "生命窃取", 0, 0, 100,false);
    public static final RegistryObject<Attribute> RECOVER_EFFECT =  attribute("recovery_effective", "治疗效果", 0, 0, Integer.MAX_VALUE,false);

    private static RegistryObject<Attribute> attribute(String key,String cn,double v,double from,double to,boolean sync){
        return FlashDays.getSimpleReg().attribute(key, cn, v, from, to, sync);
    }
    @SubscribeEvent
    public static void onAttachAttribute(EntityAttributeModificationEvent event) {
        event.getTypes().forEach(entityType -> {
            addIfNotExists(event,entityType, ModAttributes.DAMAGE_RESISTANCE.get());
            addIfNotExists(event,entityType, ModAttributes.WEAKNESS_SPECIAL_ATTACK.get());
            addIfNotExists(event,entityType, ModAttributes.REFLEXIVE_INJURY.get());
            addIfNotExists(event,entityType, ModAttributes.RANGED_DAMAGE.get());
            addIfNotExists(event,entityType, ModAttributes.DODGE.get());
            LOGGER.debug("entityType is {}",entityType);
        });
        event.add(EntityType.PLAYER, ModAttributes.ADDITION_ATTACK.get());
        event.add(EntityType.PLAYER, ModAttributes.COOLING_REDUCTION.get());
        event.add(EntityType.PLAYER, ModAttributes.USE_SPEED_UP.get());
        event.add(EntityType.PLAYER, ModAttributes.RECOVER_EFFECT.get());
        event.add(EntityType.PLAYER, ModAttributes.CRIT.get());
        event.add(EntityType.PLAYER, ModAttributes.CRIT_EFFECT.get());
        event.add(EntityType.PLAYER, ModAttributes.HEALTH_STEAL.get());

    }
    private static <T extends LivingEntity> void addIfNotExists(EntityAttributeModificationEvent event, EntityType<T> type, Attribute attribute){
        if(!event.has(type,attribute))event.add(type,attribute);
    }

    public static void init() {
        MinecraftForge.EVENT_BUS.addListener(EventPriority.LOWEST, ModAttributes::onLivingHurt);
        MinecraftForge.EVENT_BUS.addListener(EventPriority.LOWEST, ModAttributes::onEntityCure);
        MinecraftForge.EVENT_BUS.addListener(EventPriority.LOWEST, ModAttributes::onLivingDamage);
    }

    private static void onLivingDamage(LivingDamageEvent event) {
        if (!event.isCanceled()){
            DamageSource source = event.getSource();
            LivingEntity livingEntity = null;
            if (source.getEntity() instanceof LivingEntity p) {
                livingEntity = p;
            } else if (source.getDirectEntity() instanceof LivingEntity p) {
                livingEntity = p;
            }
            if (livingEntity != null) {
                var attr= HEALTH_STEAL.get();
                if(livingEntity.getAttributes().hasAttribute(attr)){
                    double value = livingEntity.getAttributeValue(attr);
                    if (value > 0)
                        livingEntity.heal((float) (event.getAmount() * value / 100d));
                }
            }
        }
    }
    private static void onLivingHurt(LivingHurtEvent event) {
        if (!event.isCanceled()){
            DamageSource source = event.getSource();
            Player player = null;
            if (source.getEntity() instanceof Player p) {
                player = p;
            } else if (source.getDirectEntity() instanceof Player p) {
                player = p;
            }
            if (player != null) {
                var attr= CRIT.get();
                if(player.getAttributes().hasAttribute(attr)){
                    double crit = player.getAttributeValue(attr);
                    if (player.getRandom().nextDouble() <= crit / 100d) {
                        var attr_critEffect =  CRIT_EFFECT.get();
                        if(player.getAttributes().hasAttribute(attr_critEffect)){
                            double effect = player.getAttributeValue(attr_critEffect);
                            event.setAmount((float) (event.getAmount() * (1d + (effect / 100d))));
                        }
                    }
                }
            }
        }
    }

    private static void onEntityCure(LivingHealEvent event) {
        BSEntityUtil.safeAttribute(event.getEntity(), RECOVER_EFFECT, v -> event.setAmount((float) (event.getAmount() * (1d + v/100d))));
    }
}
